#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "defs.h"
#include "Array.h"

static void array_dump(array_h a) {
    uint i = 0 ;
    printf("{") ;
    for(; i < array_size(a); ++i) {
        printf("%i,", *(int *)array_get(a, i)) ;
    }
    printf("}\n") ;
}

static void test_1(void) ;
static void test_2(void) ;
static void test_3(void) ;
static void test_4(void) ;
static void test_5(void) ;
static void test_6(void) ;

static void (* tests[])(void) = 
{
    test_1,
    test_2,
    test_3,
    test_4,
    test_5,
    test_6,
    NULL
} ;

int main(int argc, char **argv) {
    int test = 0 ;
    
    if(argc < 2) {
        test = sizeof(tests) / sizeof(*tests) - 1 ;
    } else {
        test = atoi(argv[1]) ;
    }
    
    if(tests[test]) {
        tests[test]() ;
    } else {
        void (** fn)(void) = tests ;
        while(*fn) {
            (*fn)() ;
            ++fn ;
        }
    }
    
    return 0 ;
}


static void test_1(void) {
    array_h a ;
    printf("test1\n") ;
    
    printf("Testing array new/delete/size.\n") ;
    
    a = array_new(sizeof(int)) ;
    
    if(a) {
        array_dump(a) ;
    } else {
        printf("array a is null. Error") ;
    }
    
    array_delete(&a) ;
    
    if(a) {
        printf("Error, a should be NULL.") ;
    }
    
    printf("!!test1!!\n") ;
}

static void test_2(void) {
    uint_t i ;
    int num = 123 ;
    array_h a, b, c, d ;
    printf("test2\n") ;
    printf("testing array_push.\n") ;
    
    a = array_new(sizeof(int)) ;
    b = array_new(sizeof(int)) ;
    c = array_new(sizeof(int)) ;
    d = array_new(sizeof(int)) ;
    
    for(i = 0; i < 25; ++i) {
        handle_t h = array_push(a, NULL) ;
        
        if(!h) printf("ERR") ;
    }
    
    for(i = 0; i < 250; ++i) {
        handle_t h = array_push(b, &num) ;
        if(!h) printf("ERR") ;
    }
    
    for(i = 0; i < 1000; ++i) {
        handle_t h = array_push(c, &num) ;
        if(!h) printf("ERR") ;
    }
    
    for(i = 0; i < 10000; ++i) {
        handle_t h = array_push(d, &num) ;
        if(!h) printf("ERR") ;
    }
    
    array_dump(b) ;
    array_dump(c) ;
    array_dump(d) ;
    
    array_delete(&a) ;
    array_delete(&b) ;
    array_delete(&c) ;
    array_delete(&d) ;
    
    printf("!!test2!!\n") ;
}

static void test_3(void) {
    uint_t i ;
    int num = 123 ;
    array_h a, b, c, d ;
    printf("test3\n") ;
    printf("testing array get.\n") ;
    a = array_new(sizeof(int)) ;
    b = array_new(sizeof(int)) ;
    c = array_new(sizeof(int)) ;
    d = array_new(sizeof(int)) ;
    
    for(i = 0; i < 10; ++i) {
        handle_t h = array_push(a, &num) ;
        if(!h) printf("ERR") ;
    }
    
    for(i = 0; i < 10; ++i) {
        handle_t h = array_push(b, &num) ;
        if(!h) printf("ERR") ;
    }
    
    for(i = 0; i < 10; ++i) {
        handle_t h = array_push(c, &num) ;
        if(!h) printf("ERR") ;
    }
    
    for(i = 0; i < 10; ++i) {
        handle_t h = array_push(d, &num) ;
        if(!h) printf("ERR") ;
    }
    
    array_dump(b) ;
    array_dump(c) ;
    array_dump(d) ;
    
    for(i = 0; i < 10; ++i) {
        if(*(int *)array_get(a, i) != num) {
            printf("ERR") ;
        }
    }
    
    for(i = 0; i < 10; ++i) {
        if(*(int *)array_get(c, i) != *(int *)array_get(b, i)) {
            printf("ERR") ;
        }
    }
    
    array_delete(&a) ;
    array_delete(&b) ;
    array_delete(&c) ;
    array_delete(&d) ;
    
    printf("!!test3!!\n") ;
}

static void test_4(void) {
    uint_t remove = 5, i = 0 ;
    uint_t num = 123 ;
    array_h a ;
    printf("test4\n") ;
    printf("testing remove.\n") ;
    a = array_new(sizeof(int)) ;
    
    for(; i < 10; ++i) {
        array_push(a, i % 2 == 0 ? &remove : &num) ;
    }
    
    array_dump(a) ;
    
    array_remove(a, &remove) ;
    
    array_dump(a) ;
    
    array_delete(&a) ;
    printf("!!test4!!\n") ;
}

static void test_5(void) {
    uint_t remove = 5, i = 0 ;
    uint_t num = 123 ;
    array_h a ;
    printf("test5\n") ;
    printf("testing array remove index.\n") ;
    a = array_new(sizeof(int)) ;
    
    for(; i < 10; ++i) {
        array_push(a, i % 2 == 0 ? &remove : &num) ;
    }
    
    array_dump(a) ;

    for(i = 0; i < array_size(a); ++i) {
        if(*(int *)array_get(a, i) == remove) {
            array_remove_ind(a, i) ;
        }
    }
    
    array_dump(a) ;
    
    array_delete(&a) ;
    printf("!!test5!!\n") ;
}

static void test_6(void) {
    printf("test6\n") ;
    test_1() ;
    test_2() ;
    test_3() ;
    test_4() ;
    test_5() ;
    printf("!!test6!!\n") ;
}
